#ifndef FACE_CLASSIFIER_HPP
#define FACE_CLASSIFIER_HPP
#include<fstream>
#include<string>
#include<vector>
#include"opencv2\opencv.hpp"

namespace fr
{
	class FaceClassifier {
	public:
		FaceClassifier() :class_num_(0), feature_dim_(1024), score_thresh_(0.40f) {}
		FaceClassifier(int feature_dim, float score_thresh):class_num_(0),
			feature_dim_(feature_dim),
			score_thresh_(score_thresh) {}

		bool load_mean(const std::string& mean_file) {
			std::ifstream file(mean_file);
			if (!file.is_open()) return false;
			feature_mean_.create(1, feature_dim_, CV_32FC1);
			for (size_t i = 0; i < feature_dim_; ++i) {
				file >> feature_mean_.at<float>(i);
			}
			return true;
		}

		std::pair<int, float> identify(const std::vector<float>& feature) {
			if (class_num_ == 0) {
				return std::make_pair(-1, 0.0f);
			}
			else {
				return first_guess(feature);
			}
		}

		std::string get_name(int id) {
			if (id < 0) {
				return "Unknown";
			}
			else {
				return known_people_[id];
			}
		}

		void add_person(const std::string& name, const std::vector<float>& feature) {
			known_people_[class_num_] = name;
			cv::Mat feature_mat = cv::Mat(1, feature_dim_, CV_32FC1, (void*)feature.data());
			cv::Mat feature_normalize;
			cv::normalize(feature_mat - feature_mean_, feature_normalize);
			features_.push_back(feature_normalize);
			++class_num_;
		}

	private:
		std::pair<int, float> first_guess(const std::vector<float>& feature) {
			std::vector<float> scores(class_num_, 0);
			cv::Mat feature_mat = cv::Mat(1, feature_dim_, CV_32FC1, (void*)feature.data());
			cv::Mat feature_normalize;
			cv::normalize(feature_mat - feature_mean_, feature_normalize);
			for (int i = 0; i < class_num_; ++i) {
				scores[i] = feature_normalize.dot(features_[i]);
			}
			auto iter = std::max_element(begin(scores), end(scores));
			int max_id = std::distance(scores.begin(), iter);
			float max_score = scores[max_id];
			std::cout << "person_id: " << known_people_[max_id] << " score: " << max_score << std::endl;
			if (max_score < score_thresh_) {
				return std::make_pair(-1, 0.0);
			}
			return std::make_pair(max_id, max_score);
		}

	private:
		std::map<int, std::string> known_people_;
		std::vector<cv::Mat> features_;
		cv::Mat feature_mean_;

		int class_num_;
		int feature_dim_;
		float score_thresh_;
		const int FaceWidth = 96;
		const int FaceHeight = 112;
	};
}

#endif // !FACE_CLASSIFIER_HPP

